//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "gpio.h"
#include "time.h"
#include "ftuart.h"
#include "udelay.h"
#include "util.h"
//#include "sean_i2c.h"
#include "bulverde.h"
//#include "commandlist.h"
//#include "tat_menu.h"
#include "gsm.h"

#define RECVBUFLEN 1024

//#define LOOPBACK_FILTER  1

char recv_buf[RECVBUFLEN];
int  change_flag = 1;

void ftuart_gpio_init()
{
    xs_setgpio_AFR(34, GPIO_AS_AF1);
    xs_setgpio_dir(34, GPIO_PIN_IN);

    xs_setgpio_AFR(37, GPIO_AS_AF3);
    xs_setgpio_dir(37, GPIO_PIN_OUT);

    xs_setgpio_AFR(26, GPIO_AS_AF3);
    xs_setgpio_dir(26, GPIO_PIN_IN);

    xs_setgpio_AFR(27, GPIO_AS_AF3);
    xs_setgpio_dir(27, GPIO_PIN_OUT);

    xs_setgpio_AFR(39, GPIO_AS_GPIO);
    xs_setgpio_dir(39, GPIO_PIN_OUT);
}

void ftuart_gpio_dein()
{
    xs_setgpio_AFR(34, GPIO_AS_AF1);
    xs_setgpio_dir(34, GPIO_PIN_IN);

    xs_setgpio_AFR(37, GPIO_AS_AF3);
    xs_setgpio_dir(37, GPIO_PIN_IN);

    xs_setgpio_AFR(26, GPIO_AS_AF3);
    xs_setgpio_dir(26, GPIO_PIN_IN);

    xs_setgpio_AFR(27, GPIO_AS_AF3);
    xs_setgpio_dir(27, GPIO_PIN_IN);

    xs_setgpio_AFR(39, GPIO_AS_GPIO);
    xs_setgpio_dir(39, GPIO_PIN_IN);
}

void bcm2121_gpio_init()
{
    //B_MODEM_WAKEUP
    xs_setgpio_AFR(114, GPIO_AS_GPIO);
    xs_setgpio_dir(114, GPIO_PIN_OUT);
    xs_setgpio_outhigh(114);

    //B_BB_HOST_WAKEUP
    xs_setgpio_AFR(38, GPIO_AS_GPIO);
    xs_setgpio_dir(38, GPIO_PIN_IN);

    //BT_32
    xs_setgpio_AFR(10, GPIO_AS_GPIO);
    xs_setgpio_dir(10, GPIO_PIN_IN);

    //BT_EJACK_RECO
    xs_setgpio_AFR(91, GPIO_AS_GPIO);
    xs_setgpio_dir(91, GPIO_PIN_IN);

    //B_BB_FLASH
    xs_setgpio_AFR(22, GPIO_AS_GPIO);
    xs_setgpio_dir(22, GPIO_PIN_OUT);

    //B_BB_RESETN
    xs_setgpio_AFR(23, GPIO_AS_GPIO);
    xs_setgpio_dir(23, GPIO_PIN_OUT);

    //B_ONKEY_N
    xs_setgpio_AFR(25, GPIO_AS_GPIO);
    xs_setgpio_dir(25, GPIO_PIN_OUT);
}

void bcm2121_on()
{

    xs_setgpio_outlow(23);

    //power on broadcom module
    xs_setgpio_outhigh(25);

    udelay(100);

    xs_setgpio_outhigh(23);

    return;
}

void bcm2121_off()
{
    xs_setgpio_outlow(25);

    return;
}

void bcm2121_download_enable()
{
    xs_setgpio_outhigh(22);
}

void bcm2121_download_disable()
{
    xs_setgpio_outlow(22);
}

#if 0
void bcm2121_s2pc(struct command_data_struct *cmd)
{
    unsigned char data[2];

    ftuart_gpio_dein();

    bcm2121_download_enable();
    bcm2121_on();
    //modify the respond data
    cmd->Command = switch_onoff_GSM;
    cmd->Para = 0;  //command parameters :0x00 0x00  means:switch to PC
    data[0] = 0;
    data[1] = 0;
    cmd->Data_Ptr = data; //command data :0x00 0x00 means:scuccessful
    cmd->Data_Len = 0x02; //command length:0x0a

    change_flag = 0; //clear the change_sw_flag,
                //let the UI know that modem has switched to pc

    do_response(*cmd); //send response message to pc
    udelay(100);
    return;
}

void bcm2121_s2bvd(struct command_data_struct *cmd)
{
    unsigned data[2];

    bcm2121_download_disable();

    gsm_ffuart_init();

    //adjust baudrate of modem to syn with bulverde btuart
    ftuart_output_byte('AT+CFUN=1 \r');
    ftuart_output_byte('\r');

    printk("adjust ok!\r\n");

    //modify the respond data
    cmd->Command = switch_onoff_GSM;
    cmd->Para = 0x01;  //command parameters :0x00 0x01.means:switch to bvd
    data[0] = 0;
    data[1] = 0;
    cmd->Data_Ptr = data; //command data :0x00 0x00. means:scuccessful
    cmd->Data_Len = 0x02; //command length:0x0a

    do_response(*cmd);//send response message to pc
    change_flag = 1; //set the change_sw_flag,
                //let the UI know that modem has switched to bulverde

    return;
}

void bcm2121_off_2bvd(struct command_data_struct *cmd)
{
    unsigned char data[2];
    bcm2121_off();

    ftuart_gpio_init();

    cmd->Command = switch_onoff_GSM;
    cmd->Para = 0x02;  //command parameters :0x00 0x01.means:switch to bvd
    data[0] = 0;
    data[1] = 0;
    cmd->Data_Ptr = data; //command data :0x00 0x00. means:scuccessful
    cmd->Data_Len = 0x02; //command length:0x0a

    do_response(*cmd);//send response message to pc
    change_flag = 1; //set the change_sw_flag

    return;
}

int swt_onoff_gsm(struct command_data_struct command_data)
{
    unsigned short para;
    unsigned char data[2];

    bcm2121_gpio_init();

    para = command_data.Para;
    if (para != 0 && para != 0x01 && para != 0x02) //if para err,send failed message to pc
    {
        //wls_printf("Error: %s\n", get_error_string() );

        command_data.Command = switch_onoff_GSM;
        //command_data.Para = 0x01;
        data[0] = 0;
        data[1] = 1;
        command_data.Data_Ptr = data; //command data :0x00 0x01. means:failture
        command_data.Data_Len = 0x02; //command length:0x0a
        do_response(command_data); //send failture message to pc
        return FALSE;
    }
    if (para == 0) //switch to PC
    {
        bcm2121_s2pc(&command_data);
    }
    if (para == 0x01) //switch to bulverde
    {
        bcm2121_s2bvd(&command_data);
    }
    if (para == 0x02) {
        bcm2121_off_2bvd(&command_data);
    }
    return TRUE;
}

int change_sw_flag(struct command_data_struct command_data)
{
    command_data.Para = (unsigned short )change_flag; //send change_flage to PC to tell that modem
                                //switch to bulverde or to PC.
    do_response(command_data);
    return TRUE;
}

#ifdef LOOPBACK_FILTER
int atcmd_loopback_filter(struct command_data_struct *cmd)
{
    int i;
    int count;
    int head,trail;
    int loopback_len;
    char flag;

    i = 0;
    count = 0;
    head = 0;
    trail = 0;
    //filter loopback data from modem
    for (i = 0;i < cmd->Data_Len;i++) {
        switch (count) {
            case 0:
                if( cmd->Data_Ptr[i] == 0x0d ) count = 1;
                if (cmd->Data_Ptr[i] == 0x41 || cmd->Data_Ptr[i] == 0x61) {
                    count = 8;
                    flag = 1;
                }
                break;
            case 1:
                if (cmd->Data_Ptr[i] == 0x0a)
                    count = 2;
                else
                    count = 0;
                break;
            case 2:
                if (cmd->Data_Ptr[i] == 0x41 || cmd->Data_Ptr[i] == 0x61)
                    count = 3;
                else
                    count = 0;
                break;
            case 3:
                if (cmd->Data_Ptr[i] == 0x54 || cmd->Data_Ptr[i] == 0x74) {
                    count = 4;
                    head = i-3;
                }
                else
                    count = 0;
                break;
            case 4:
                if (cmd->Data_Ptr[i] == 0x0d)
                    count = 5;
                else
                    count = 4;
                break;
            case 5:
                if (cmd->Data_Ptr[i] == 0x0a) {
                    count = 6;
                    trail = i;
                }
                else {
                    count = 7;
                    trail = i-1;
                }
                break;
            case 8:
                if (cmd->Data_Ptr[i] == 0x54 || cmd->Data_Ptr[i] == 0x74) {
                    count = 4;
                    head = i-1;
                }
                else
                    count = 0;
                break;
            default:break;
        }
        if (count == 6 || count == 7) break;
    }

    if (trail != 0) {
        loopback_len = trail - head + 1;
        //for ( i = head;i<=trail;i++)
        // cmd->Data_Ptr[i] = cmd->Data_Ptr[i + loopback_len];
        cmd->Data_Ptr = &cmd->Data_Ptr[head+loopback_len];

        cmd->Data_Len = cmd->Data_Len - loopback_len;
    }

    return TRUE;
}
#endif

void bvd_send_cmd(unsigned char *cmdstr, int strlen)
{
    int i;

    for (i = 0; i < strlen; i++) {
        ftuart_output_byte((const char)cmdstr[i]);
    // printk("cmdstr:%04x *",cmdstr[i]);
    }
    return;
}

void bvd_recv_cmd(struct command_data_struct *cmd)
{
    unsigned char ch;
    int c;
    int i;

    ftuart_clear_rx();

    for (i = 0; i < RECVBUFLEN; i++) {
        c = ftuart_input_byte((char *)&ch);

        if(c == 0) break;
        cmd->Data_Ptr[i] = (unsigned char)ch;
    // printk("input:%02x **",cmd->Data_Ptr[i]);
    }
    cmd->Data_Len = i;
    //printk("len:%04x **",cmd->Data_Len);

    return;
}

int gsm_ffuart_init()
{
    ftuart_gpio_init();
    bcm2121_gpio_init();

    bcm2121_download_disable();
    bcm2121_on();
    ftuart_init(baud115k2);
    udelay(100);

    return 1;
}

int send_atcmd_gsm(struct command_data_struct command_data)
{
    unsigned int i;
    struct command_data_struct *cmd;

    //gsm_ffuart_init();

    cmd = &command_data;
    bvd_send_cmd(cmd->Data_Ptr,cmd->Data_Len); //send AT command to gsm
    bvd_recv_cmd(cmd);
#ifdef LOOPBACK_FILTER
    atcmd_loopback_filter(cmd);
#endif
    //printk("cmd2->Len:%04x ***",cmd->Data_Len);
    do_response(*cmd);
    return TRUE;
}
#endif /* 0 */
